#include "ship_handler.h"
#include "game.h"
#include "input_handler.h"
#include "texture_manager.h"

ShipHandler* ShipHandler::s_pInstance = NULL;

ShipHandler::ShipHandler() {
    m_placingCompleteP = false;
    m_placingCompleteE = false;
    m_bReleasedR = true;
    m_bReleasedL = true;
    playerTurn = true;
    for (int x = 0; x < 10; x++) {
        for (int y = 0; y < 10; y++) {
            m_playerBoard[x][y] = NULL;
            m_enemyBoard[x][y] = NULL;
            m_playerHitInfo[x][y] = NULL;
            m_enemyHitInfo[x][y] = NULL;
        }
    }
}

void ShipHandler::addShips() {
    for (int i = 1; i <= 5; i++) { // 5: ships/fleet
        m_playerShips.push_back(new Ship(i, Ship::LEFT_RIGHT, Ship::PLAYER));
        m_enemyShips.push_back(new Ship(i, Ship::LEFT_RIGHT, Ship::ENEMY));
    }
}

void ShipHandler::drawShips() {
    for (unsigned int p = 0; p < m_playerShips.size(); p++) {
        if (static_cast<int>(p) == getFirstUnplacedShip(Ship::PLAYER) || m_playerShips[p]->placed())
            m_playerShips[p]->draw();
    }
    for (unsigned int e = 0; e < m_enemyShips.size(); e++)
        m_enemyShips[e]->draw();
    drawHits();
}

int ShipHandler::getFirstUnplacedShip(Ship::Owner owner) const {
    if (owner == Ship::PLAYER) {
        for (unsigned int i = 0; i < m_playerShips.size(); i++) {
            if (!m_playerShips[i]->placed())
                return i;
        }
    } else {
        for (unsigned int i = 0; i < m_enemyShips.size(); i++) {
            if (!m_enemyShips[i]->placed())
                return i;
        }
    }
    return -1;
}

void ShipHandler::updateShips() {
    if (playerTurn) {
        Vector2D* pMousePos = TheInputHandler::Instance()->getMousePosition();
        if (pMousePos->getX() > 25 && pMousePos->getX() < 375 && pMousePos->getY() > 150 && pMousePos->getY() < 500) {
            // player field
            int shipID = getFirstUnplacedShip(Ship::PLAYER);
            if (shipID == -1) {
                m_placingCompleteP = true;
                return;
            }
            int cx, cy;
            cx = static_cast<int>(pMousePos->getX() - 25) / 35;
            cy = static_cast<int>(pMousePos->getY() - 150) / 35;
            m_playerShips[shipID]->position(cx, cy);
            if (TheInputHandler::Instance()->getMouseButtonState(RIGHT) && m_bReleasedR) {
                m_playerShips[shipID]->changeDirection();
                m_bReleasedR = false;
            } else {
                if (!TheInputHandler::Instance()->getMouseButtonState(RIGHT))
                    m_bReleasedR = true;
            }
            if (TheInputHandler::Instance()->getMouseButtonState(LEFT) && m_bReleasedL) {
                if (canAddShip(cx, cy, m_playerShips[shipID])) {
                    add(cx, cy, m_playerShips[shipID]);
                    m_playerShips[shipID]->placed(true);
                    playerTurn = !playerTurn;
                }
                m_bReleasedL = false;
            } else {
                if (!TheInputHandler::Instance()->getMouseButtonState(LEFT))
                    m_bReleasedL = true;
            }
        }
        if (pMousePos->getX() > 425 && pMousePos->getX() < 775 && pMousePos->getY() > 150 && pMousePos->getY() < 500) {
            // enemy field
            if (!m_placingCompleteP)
                return;
            int cx, cy;
            cx = static_cast<int>(pMousePos->getX() - 425) / 35;
            cy = static_cast<int>(pMousePos->getY() - 150) / 35;
            if (TheInputHandler::Instance()->getMouseButtonState(LEFT) && m_bReleasedL) {
                if (m_playerHitInfo[cx][cy] != NULL)
                    return;
                if (m_enemyBoard[cx][cy] != NULL) {
                    m_enemyShips[m_enemyBoard[cx][cy] - 1]->decLife();
                    m_playerHitInfo[cx][cy] = 1;
                } else {
                    m_playerHitInfo[cx][cy] = -1;
                }
                playerTurn = !playerTurn;
                m_bReleasedL = false;
            } else {
                if (!TheInputHandler::Instance()->getMouseButtonState(LEFT))
                    m_bReleasedL = true;
            }
        }
    } else {//enemy turn
        // TODO : fix AI
        int cx, cy, d;
        cx = static_cast<int>(1.0 * rand() / (RAND_MAX + 1) * 10);
        cy = static_cast<int>(1.0 * rand() / (RAND_MAX + 1) * 10);
        d = static_cast<int>(1.0 * rand() / (RAND_MAX + 1) * 2);
        if (!m_placingCompleteE) {
            int shipID = getFirstUnplacedShip(Ship::ENEMY);
            if (shipID == -1) {
                m_placingCompleteE = true;
                return;
            }
            m_enemyShips[shipID]->position(cx, cy);
            if (d == 1) {
                m_enemyShips[shipID]->changeDirection();
            }
            if (canAddShip(cx, cy, m_enemyShips[shipID])) {
                add(cx, cy, m_enemyShips[shipID]);
                m_enemyShips[shipID]->placed(true);
                playerTurn = !playerTurn;
            }
        } else {
            if (m_enemyHitInfo[cx][cy] != NULL)
                return;
            if (m_playerBoard[cx][cy] != NULL) {
                m_playerShips[m_playerBoard[cx][cy] - 1]->decLife();
                m_enemyHitInfo[cx][cy] = 1;
            } else {
                m_enemyHitInfo[cx][cy] = -1;
            }
            playerTurn = !playerTurn;
        }
    }
}

bool ShipHandler::canAddShip(int cx, int cy, Ship* ship) {
    int x = cx, y = cy;
    for (unsigned int i = 0; i < ship->size(); i++) {
        if (ship->direction() == Ship::LEFT_RIGHT) {
            x = cx + i;
            if (x > 9)
                return false;
        } else {
            y = cy + i;
            if (y > 9)
                return false;
        }
        if (ship->owner() == Ship::PLAYER) {
            if (m_playerBoard[x][y] != NULL)
                return false;
        } else {
            if (m_enemyBoard[x][y] != NULL)
                return false;
        }
    }
    return true;
}

void ShipHandler::clearShips() {
    m_playerShips.clear();
    m_enemyShips.clear();
    m_placingCompleteP = false;
    m_placingCompleteE = false;
    m_bReleasedR = true;
    m_bReleasedL = true;
    playerTurn = true;
    for (int x = 0; x < 10; x++) {
        for (int y = 0; y < 10; y++) {
            m_playerBoard[x][y] = NULL;
            m_enemyBoard[x][y] = NULL;
            m_playerHitInfo[x][y] = NULL;
            m_enemyHitInfo[x][y] = NULL;
        }
    }
}

void ShipHandler::add(int cx, int cy, Ship* ship) {
    int x = cx, y = cy;
    for (unsigned int i = 0; i < ship->size(); i++) {
        if (ship->direction() == Ship::LEFT_RIGHT)
            x = cx + i;
        else
            y = cy + i;
        if (ship->owner() == Ship::PLAYER)
            m_playerBoard[x][y] = ship->size();
        else
            m_enemyBoard[x][y] = ship->size();
    }
}

void ShipHandler::drawHits() {
    for (int x = 0; x < 10; x++) {
        for (int y = 0; y < 10; y++) {
            if (m_playerHitInfo[x][y] > 0) {
                TheTextureManager::Instance()->drawFrame("hit",
                x * 35 + 425, y * 35 + 150, 100, 100, 0, 0, TheGame::Instance()->getRenderer(), 0, 191, 0.35);
            } else {
                if (m_playerHitInfo[x][y] < 0) {
                    TheTextureManager::Instance()->drawFrame("miss",
                    x * 35 + 425, y * 35 + 150, 100, 100, 0, 0, TheGame::Instance()->getRenderer(), 0, 191, 0.35);
                }
            }
            if (m_enemyHitInfo[x][y] > 0) {
                TheTextureManager::Instance()->drawFrame("hit",
                x * 35 + 25, y * 35 + 150, 100, 100, 0, 0, TheGame::Instance()->getRenderer(), 0, 191, 0.35);
            } else {
                if (m_enemyHitInfo[x][y] < 0) {
                    TheTextureManager::Instance()->drawFrame("miss",
                    x * 35 + 25, y * 35 + 150, 100, 100, 0, 0, TheGame::Instance()->getRenderer(), 0, 191, 0.35);
                }
            }
        }
    }
}

int ShipHandler::gameFinished() {
    // -1: enemy win, 0: unfinished, 1: player win;
    int p = 0, e = 0;
    for (unsigned int i = 0; i < m_playerShips.size(); i++) {
        if (m_playerShips[i]->alive())
            p++;
    }
    if (p == 0)
        return -1;
    for (unsigned int i = 0; i < m_enemyShips.size(); i++) {
        if (m_enemyShips[i]->alive())
            e++;
    }
    if (e == 0)
        return 1;
    return 0;
}
